package general;

import jsonObjects.Attributes;
import jsonObjects.Files;
import jsonObjects.Profile;
import org.apache.commons.vfs2.FileChangeEvent;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.log4j.Logger;
import serverHandling.SessionObjects;

import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class FileUtils {
    private static Logger log = Logger.getLogger(FileUtils.class);

    public static String getFileName(URL url) {
        int slashIndex = url.getFile().lastIndexOf('/');
        int dotIndex = url.getFile().lastIndexOf('.', slashIndex);

        if (dotIndex == -1)
            return url.getFile().substring(slashIndex + 1);
        else
            return url.getFile().substring(slashIndex + 1, dotIndex);

    }

    /**
     * @param url  url do pliku
     * @param sign znak konczacy url ( jezeli specyficzny np. / )
     * @return String
     */
    public static String getFileName(URL url, String sign) {
        int slashIndex = url.getFile().lastIndexOf(sign);
        int dotIndex = url.getFile().lastIndexOf('.', slashIndex);

        if (dotIndex == -1)
            return url.getFile().substring(slashIndex + 1);
        else
            return url.getFile().substring(slashIndex + 1, dotIndex);
    }

    public static String getProperFileUrl(String url) {
        String mainFolder = GlobalProperties.getFolderMonit().replace("\\", "\\");
        String tmp = url.replace(mainFolder, "").replace(getFileName(url), "");
        return tmp.replace("\\", "/");
    }

    public static String getProperFileFullUrl(String url) {
        String mainFolder = GlobalProperties.getFolderMonit().replace("\\", "\\");
        String tmp = url.replace(mainFolder, "");
        return tmp.replace("\\", "/");
    }

    public static String getFileName(String url) {
        int slashIndex = url.lastIndexOf('\\');
        int dotIndex = url.lastIndexOf('.', slashIndex);

        if (dotIndex == -1) return url.substring(slashIndex + 1);
        else
            return url.substring(slashIndex + 1, dotIndex);

    }

    public static Properties loadProperties(File fileProperties) {
        Properties tmp = new Properties();
        InputStream is;
        try {
            is = new FileInputStream(fileProperties);
            tmp.load(is);
        } catch (java.io.FileNotFoundException e) {
            log.error(e.getMessage());
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return tmp;
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static boolean renameFile(String oldPath, String newPath) throws IOException {
        File srcFile = new File(oldPath);
        boolean hasSucceeded = false;
        try {
            File destFile = new File(newPath);
            if (destFile.exists()) {
                if (!destFile.delete()) {
                    throw new IOException(oldPath + " was not successfully renamed to " + newPath);
                }
            }
            if (!srcFile.renameTo(destFile)) {
                log.info("Error occurred while trying to rename file");
            } else {
                hasSucceeded = true;
            }
        } finally {
            if (hasSucceeded) {
                srcFile.delete();
            }
        }
        return hasSucceeded;
    }

    public static boolean deleteFileSafe(File f) {
        if (!f.exists())
            throw new IllegalArgumentException("Delete: no such file or directory: " + f.getName());
        if (!f.canWrite())
            throw new IllegalArgumentException("Delete: write protected: " + f.getName());
        if (f.isDirectory()) {
            String[] files = f.list();
            if (files.length > 0)
                throw new IllegalArgumentException("Delete: directory not empty: " + f.getName());
        }
        boolean success = f.delete();
        if (!success)
            throw new IllegalArgumentException("Delete: deletion failed");

        return success;
    }

    public static boolean deleteFileUnsafe(File f) {
        boolean success = false;
        try {
            if (f.exists())
                success = f.delete();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return success;
    }

    public static String getExtension(File f) {
        String ext = null;
        String s = f.getName();
        int i = s.lastIndexOf('.');

        if (i > 0 && i < s.length() - 1)
            ext = s.substring(i + 1).toLowerCase();

        if (ext == null)
            return "";
        return ext;
    }


    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static void dopiszZmianyDoProperties(Files event, Profile profile, Attributes[] fileAttributes) throws InterruptedException {
        FileOutputStream fos = null;
        File propFile = null;

        try {
            String folderPath = GlobalProperties.getFolderMonit() + profile.getName() + "\\";
            propFile = new File(folderPath + profile.getName() + ".properties");

            // ujawnianie pliku properties
            GlobalProperties.unhide(propFile);
            // jezeli nie istnieje to tworzymy
            if (!propFile.exists()) {
                propFile.createNewFile();
            }
            // otwieramy strumien zapisu do pliku properties
            fos = new FileOutputStream(propFile);
            // tworzymy obiekt typu Properties
            Properties properties = FileUtils.loadProperties(propFile);

            // tmp -> nazwa pliku dla ktorego sprawdzamy wartosc property
            String tmp;
            // Atrybuty od ich watośći oddzielone znakiem "?"
            for (Attributes at : (fileAttributes.length == 0 ? profile.getAttributes() : fileAttributes)) {
                tmp = event.getName() + "?" + at.getName();
                if (properties.get(tmp) == null)
                    properties.put(tmp, at.getDefault_value());
                else
                    properties.put(tmp, at.getValue());

            }

            // zapisywanie zmian do pliku
            properties.store(fos, "");
            // ukrywanie pliku
            if (!propFile.isHidden())
                GlobalProperties.hide(propFile);
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            // zamykamy strumień
            try {
                if (fos != null) fos.close();
                if (propFile != null)
                    GlobalProperties.hide(propFile);
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }


    public static String getPropertiesFilePath(FileChangeEvent event) throws FileSystemException {
        String propertyFileNameWithPath;
        propertyFileNameWithPath = event.getFile().getParent().getURL().getPath()
                + "/" + FileUtils.getFileName(event.getFile().getParent().getURL(), "/") + ".properties";
        propertyFileNameWithPath = propertyFileNameWithPath.substring(3);// ucinanie znakow '///'
        return propertyFileNameWithPath;
    }

    public static Map<Attributes, String> getAtrybutyPliku(String plik, Profile profile) {
        Map<Attributes, String> mapAttributeValue = new HashMap<Attributes, String>();
        Attributes[] profAtr = getProfileAtributes(profile.getName());
        Properties properties = FileUtils.loadProperties(getProfilePropertyFile(profile));

        String tmp;
        for (Attributes at : profAtr) {
            tmp = plik + "?" + at.getName();
            mapAttributeValue.put(at, properties.get(tmp) != null ? (String) properties.get(tmp) : "");
        }

        return mapAttributeValue;
    }

    public static File getProfilePropertyFile(Profile profile) {
        String folderPath = GlobalProperties.getFolderMonit() + profile.getName() + "\\";
        return new File(folderPath + profile.getName() + ".properties");
    }

    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static void deleteAttributeFromFile(Files file, Profile profile) throws InterruptedException {
        // jezeli wyslano modyfikuj plik properties
        FileOutputStream fos = null;
        File propFile = null;

        try {
            String folderPath = GlobalProperties.getFolderMonit() + profile.getName() + "\\";
            propFile = new File(folderPath + profile.getName() + ".properties");

            // ujawnianie pliku properties
            GlobalProperties.unhide(propFile);
            // jezeli nie istnieje to tworzymy
            if (!propFile.exists()) {
                propFile.createNewFile();
            }
            // otwieramy strumien zapisu do pliku properties
            fos = new FileOutputStream(propFile);
            // tworzymy obiekt typu Properties
            Properties properties = FileUtils.loadProperties(propFile);

            // tmp -> nazwa pliku dla ktorego sprawdzamy wartosc property
            String tmp;
            // Atrybuty od ich watośći oddzielone znakiem "?"
            for (Attributes at : profile.getAttributes()) {
                tmp = file.getName() + "?" + at.getName();
                properties.remove(tmp);
            }

            // zapisywanie zmian do pliku
            properties.store(fos, "");
            // ukrywanie pliku
            if (!propFile.isHidden())
                GlobalProperties.hide(propFile);
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            // zamykamy strumień
            try {
                if (fos != null) fos.close();
                if (propFile != null)
                    GlobalProperties.hide(propFile);
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }

    public static Attributes[] getProfileAtributes(String profile) {
        for (Profile p : SessionObjects.getProfiles())
            if (p.getName().equals(profile))
                return p.getAttributes();
        return null;
    }

    @SuppressWarnings("UnusedDeclaration")
    public static Profile getProfileByName(String profile) {
        for (Profile p : SessionObjects.getProfiles())
            if (p.getName().equals(profile))
                return p;
        return null;
    }

    @SuppressWarnings({"ConstantConditions", "ResultOfMethodCallIgnored"})
    public static void dopiszZmianyDoProperties(FileChangeEvent event, String profilName) throws InterruptedException {
        // jezeli wyslano modyfikuj plik properties
        FileOutputStream fos = null;
        Attributes[] profAtr = FileUtils.getProfileAtributes(profilName);
        File propFile = null;

        try {
            // otwieranie pliku
            propFile = new File(FileUtils.getPropertiesFilePath(event));
            // ujawnianie pliku properties
            GlobalProperties.unhide(propFile);
            // jezeli nie istnieje to tworzymy
            if (!propFile.exists()) {
                propFile.createNewFile();
            }
            // otwieramy strumien zapisu do pliku properties
            fos = new FileOutputStream(propFile);
            // tworzymy obiekt typu Properties
            Properties properties = FileUtils.loadProperties(propFile);

            // tmp -> nazwa pliku dla ktorego sprawdzamy wartosc property
            String tmp;
            // Atrybuty od ich watośći oddzielone znakiem "?"
            for (Attributes at : profAtr) {
                tmp = FileUtils.getFileName(event.getFile().getURL()) + at.getName();
                if (properties.get(tmp) == null)
                    properties.put(FileUtils.getFileName(event.getFile().getURL()) + "?" + at.getName(), GlobalProperties.DEFAULT_ATTRIBUTE);
            }

            // zapisywanie zmian do pliku
            properties.store(fos, "");
            // ukrywanie pliku
            if (!propFile.isHidden())
                GlobalProperties.hide(propFile);
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            // zamykamy strumień
            try {
                if (fos != null) fos.close();
                if (propFile != null)
                    GlobalProperties.hide(propFile);
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }
    
    public static String MD5(String md5) {
	try {
	    java.security.MessageDigest md = java.security.MessageDigest
		    .getInstance("MD5");
	    byte[] array = md.digest(md5.getBytes());
	    StringBuffer sb = new StringBuffer();
	    for (int i = 0; i < array.length; ++i) {
		sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100)
			.substring(1, 3));
	    }
	    return sb.toString();
	} catch (java.security.NoSuchAlgorithmException e) {
	}
	return null;
    }

}
